

#include "../topic_messenger.h"
#include "../topic_messenger_conf.h"

#if topic_messenger_platform_esp
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#endif

#if topic_messenger_compile_en

static topic_messenger_subscribe_t *register_head = NULL;
static topic_messenger_subscribe_t *list_branch_head = NULL;
static uint16_t register_count = 0;

static topic_messenger_subscribe_t *chek_has_register(topic_messenger_handle_t handle);

#if topic_messenger_support_rtos
static topic_messenger_mutex_cb_t mutex_cb;
#if topic_messenger_platform_esp
static SemaphoreHandle_t topic_mutex_handle = NULL;
static uint8_t init_flag = 0;
static topic_messenger_ret_t topic_messenger_mutex_register(topic_messenger_mutex_cb_t *cb)
#else
topic_messenger_ret_t topic_messenger_mutex_register(topic_messenger_mutex_cb_t *cb)
#endif
{
    mutex_cb = *cb;
    return TOPIC_MESSENGER_SUCCESS;
}
#endif

uint16_t topic_messenger_subscribe_count(void)
{
    return register_count;
}

static uint16_t get_key_sum(const char *key)
{
    uint16_t sum = 0, i;
    const uint8_t *dat = (const uint8_t *)key;
    i = strlen(key);
    while (i--)
        sum += *dat++;
    return sum;
}

static topic_messenger_subscribe_t *chek_has_register(topic_messenger_handle_t handle)
{
    topic_messenger_handle_t move = (topic_messenger_handle_t)register_head;
    while (move != NULL)
    {
        if (handle->key_sum != move->key_sum) // 键名不符合
        {
            move = move->next;
            continue;
        }
        if (strcmp(handle->key, move->key) == 0) // 键名符合
        {
            list_branch_head = move;
            while (handle != move && move != NULL)
                move = move->same_next;
            return move;
        }
        move = move->next;
    }
    return NULL;
}

static uint8_t chek_has_register_key(const char *key)
{
    uint16_t sum = get_key_sum(key);
    topic_messenger_handle_t move = (topic_messenger_handle_t)register_head;

    while (move != NULL)
    {
        if (move->key_sum != sum) // 键名不符
        {
            move = move->next;
            continue;
        }
        if (strcmp(key, move->key) == 0) // 找到键
        {
            list_branch_head = move;
            return 1;
        }
        move = move->next;
    }
    return 0;
}

static topic_messenger_ret_t deL_handle(topic_messenger_handle_t handle)
{
    topic_messenger_subscribe_t *tmp = chek_has_register(handle);

    if (tmp == NULL)
        return TOPIC_MESSENGER_NO_SUBCRIBE;

    if (tmp == register_head) // 表头
    {
        if (register_head == register_head->last) // 仅一个主节点
        {
            if (tmp->same_next != NULL) // 名下有分支节点
            {
                tmp->same_next->same_last = tmp->same_last;
                tmp->same_next->same_flag = 0; // 回到主路
                register_head = tmp->same_next;
            }
            else
                register_head = NULL;
        }
        else // 多节点
        {
            if (tmp->same_next != NULL) // 名下有分支节点
            {
                tmp->same_next->same_flag = 0; // 回到主路
                tmp->same_next->same_last = tmp->same_last;
                tmp->same_next->next = tmp->next;
                tmp->same_next->last = tmp->last;
                tmp->next->last = tmp->same_next; // 更新前后节点
                register_head = tmp->same_next;
            }
            else
            {
                register_head->next->last = register_head->last; // 尾巴
                register_head = register_head->next;
            }
        }
    }
    else if (tmp == register_head->last) // 表尾
    {
        if (tmp->same_next != NULL) // 名下有分支节点
        {
            tmp->same_next->same_flag = 0; // 回到主路
            tmp->same_next->same_last = tmp->same_last;
            tmp->same_next->next = tmp->next;
            tmp->same_next->last = tmp->last;
            tmp->next->last = tmp->same_next; // 更新前后节点
            register_head->last = tmp->same_next;
        }
        else // 无分支节点
        {
            register_head->last = tmp->last; // 更新表尾
            tmp->last->next = NULL;          // 表尾结束
        }
    }
    else // 中间节点
    {
        if (tmp->same_flag == 1) // 是分支节点
        {
            tmp->same_last->same_next = tmp->same_next; // 更新前后节点
            if (tmp->same_next != NULL)                 // 不是分支尾
                tmp->same_next->same_last = tmp->same_last;
            else
                list_branch_head->same_last = tmp->same_last; // 分支尾
        }
        else // 主路节点
        {
            if (tmp->same_next != NULL) // 名下有分支节点
            {
                tmp->same_next->same_flag = 0; // 回到主路
                tmp->same_next->same_last = tmp->same_last;
                tmp->same_next->next = tmp->next;
                tmp->same_next->last = tmp->last;
                tmp->next->last = tmp->same_next; // 更新前后节点
                tmp->last->next = tmp->same_next;
            }
            else
            {
                tmp->last->next = tmp->next; // 更新前后节点
                tmp->next->last = tmp->last;
            }
        }
    }

    topic_messenger_free_func((void *)tmp->key);
    topic_messenger_free_func(tmp);
    register_count--;

    return TOPIC_MESSENGER_SUCCESS;
}

topic_messenger_ret_t topic_messenger_msg(const char *theme, void *userdata, size_t lenth)
{
    uint16_t sum = 0;
    topic_messenger_ret_t ret = TOPIC_MESSENGER_NO_SUBCRIBE;
#if topic_messenger_support_rtos
    static uint8_t busy = 0;
    if (busy == 0)
        mutex_cb.mutex_get_cb();
    busy++;
#endif

    topic_messenger_subscribe_t *move = register_head;

    sum = get_key_sum(theme);

    while (move != NULL)
    {
        if (move->key_sum != sum) // 键名不符
        {
            move = move->next;
            continue;
        }

        if (strcmp(theme, move->key) == 0) // 找到键
        {
            while (move != NULL) // 执行所有分支回调
            {
                move->_cb(userdata, lenth);
                move = move->same_next;
            }
            ret = TOPIC_MESSENGER_SUCCESS;
            break;
        }
        move = move->next;
    }
#if topic_messenger_support_rtos
    busy--;
    if (busy == 0)
        mutex_cb.mutex_give_cb();
#endif
    return ret;
}

#if (topic_messenger_support_rtos && topic_messenger_platform_esp)
static void topic_take_key()
{
    xSemaphoreTake(topic_mutex_handle, portMAX_DELAY);
}

static void topic_give_key()
{
    xSemaphoreGive(topic_mutex_handle);
}
#endif

topic_messenger_ret_t topic_messenger_subscribe(topic_messenger_handle_t *handle, const char *theme, topic_messenger_cb_t cb)
{

#if (topic_messenger_support_rtos && topic_messenger_platform_esp)
    if (init_flag == 0)
    {
        init_flag = 1;
        topic_mutex_handle = xSemaphoreCreateMutex();
        topic_messenger_mutex_cb_t cfg = {
            .mutex_get_cb = topic_take_key,
            .mutex_give_cb = topic_give_key};
        topic_messenger_mutex_register(&cfg);
    }
#endif

    size_t _len = 0;
    topic_messenger_subscribe_t *tmp = topic_messenger_malloc_func(sizeof(topic_messenger_subscribe_t));

    if (tmp == NULL)
        return TOPIC_MESSENGER_MALLOC_FAIL;

    _len = strlen(theme) + 1;
    tmp->key = topic_messenger_malloc_func(_len);
    if (tmp->key == NULL)
    {
        topic_messenger_free_func(tmp);
        return TOPIC_MESSENGER_MALLOC_FAIL;
    }
    memcpy((void *)tmp->key, theme, _len);

    tmp->same_flag = chek_has_register_key(theme);
    tmp->key_sum = get_key_sum(theme);
    tmp->next = NULL;
    tmp->last = NULL;
    tmp->same_next = NULL;
    tmp->same_last = NULL;
    tmp->_cb = cb;
    tmp->priority = TOPIC_MESSENGER_PRIORITY_LOW;

#if topic_messenger_support_rtos
    mutex_cb.mutex_get_cb();
#endif

    if (handle != NULL)
        *handle = tmp;

    if (register_head == NULL) // 第一个节点
    {
        register_head = tmp;       // 头
        register_head->last = tmp; // 尾
    }
    else // 不是第一个节点
    {
        if (tmp->same_flag == 1) // 分支节点
        {
            list_branch_head->same_last->same_next = tmp; // 更新前后节点
            tmp->same_last = list_branch_head->same_last;
            list_branch_head->same_last = tmp;
        }
        else
        {
            register_head->last->next = tmp;
            tmp->last = register_head->last;
            register_head->last = tmp;
            tmp->same_last = tmp;
        }
    }

#if topic_messenger_support_rtos
    mutex_cb.mutex_give_cb();
#endif
    register_count++;

    return TOPIC_MESSENGER_SUCCESS;
}

static topic_messenger_subscribe_t *get_priority_head(topic_messenger_priority_t priority)
{
    topic_messenger_subscribe_t *tmp = register_head;
    while (tmp != NULL)
    {
        if (tmp->priority <= (uint8_t)priority)
        {
            return tmp;
        }
        tmp = tmp->next;
    }
    return NULL;
}

topic_messenger_ret_t topic_messenger_set_priority(topic_messenger_handle_t handle, const char *theme, topic_messenger_priority_t priority)
{
    topic_messenger_subscribe_t *tmp = NULL;
    topic_messenger_ret_t ret = TOPIC_MESSENGER_NO_SUBCRIBE;

#if topic_messenger_support_rtos
    mutex_cb.mutex_get_cb();
#endif

    if (handle != NULL)
    {
        tmp = chek_has_register(handle);
        if (tmp == NULL)
            goto exit;
        if (tmp->same_flag == 1)
        {
            chek_has_register_key(tmp->key);
            tmp = list_branch_head;
        }
    }
    else if (theme != NULL)
    {
        if (chek_has_register_key(theme))
            tmp = list_branch_head;
    }
    else
        goto exit;

    if (tmp == NULL)
        goto exit;

    if (tmp->priority == priority)
    {
        ret = TOPIC_MESSENGER_SUCCESS;
        goto exit;
    }

    topic_messenger_subscribe_t *ins_node = get_priority_head(priority);

    if (tmp == register_head) // 头部
    {
        if (register_count == 1 || ins_node == register_head) // 特殊情况
            goto change_priority;
        else if (register_count > 1 && ins_node == register_head->next) // 特殊情况
            goto change_priority;

        // 去掉节点
        register_head = tmp->next;
        register_head->last = tmp->last;
    }
    else if (tmp == register_head->last) // 尾部
    {
        if (ins_node == NULL || tmp == ins_node) // 特殊情况
            goto change_priority;

        // 去掉节点
        register_head->last = tmp->last;
        register_head->last->next = NULL;
    }
    else // 中间
    {
        if (tmp == ins_node || ins_node == tmp->next) // 中间特殊情况
            goto change_priority;

        // 去掉节点
        tmp->last->next = tmp->next;
        tmp->next->last = tmp->last;
    }

    // 插入节点
    if (ins_node == register_head) // 插到头部
    {
        tmp->last = register_head->last;
        tmp->next = register_head;

        register_head->last = tmp;
        register_head = tmp;
    }
    else if (ins_node == NULL) // 插到尾部
    {
        tmp->next = NULL;
        tmp->last = register_head->last;

        register_head->last = tmp;
        tmp->last->next = tmp;
    }
    else // 插到中间
    {
        tmp->last = ins_node->last;
        tmp->next = ins_node;

        ins_node->last = tmp;
        tmp->last->next = tmp;
    }

change_priority:
    tmp->priority = (uint8_t)priority;
    ret = TOPIC_MESSENGER_SUCCESS;

exit:

#if topic_messenger_support_rtos
    mutex_cb.mutex_give_cb();
#endif
    return ret;
}

topic_messenger_ret_t topic_messenger_del(topic_messenger_handle_t handle)
{
#if topic_messenger_support_rtos
    mutex_cb.mutex_get_cb();
    topic_messenger_ret_t ret = deL_handle(handle);
    mutex_cb.mutex_give_cb();
    return ret;
#else
    return deL_handle(handle);
#endif
}

topic_messenger_ret_t topic_messenger_del_by_theme(const char *theme)
{
    topic_messenger_ret_t ret = TOPIC_MESSENGER_NO_SUBCRIBE;
#if topic_messenger_support_rtos
    mutex_cb.mutex_get_cb();
#endif

    if (chek_has_register_key(theme) == 0)
        goto exit;

    topic_messenger_subscribe_t *tmp = list_branch_head->next;
    topic_messenger_subscribe_t *tmp_next = NULL;

    while (tmp != NULL)
    {
        tmp_next = tmp->next;
        topic_messenger_free_func((void *)tmp->key);
        topic_messenger_free_func(tmp);
        tmp = tmp_next;
        register_count--;
    }
    deL_handle(list_branch_head);
    ret = TOPIC_MESSENGER_SUCCESS;
exit:
#if topic_messenger_support_rtos
    mutex_cb.mutex_give_cb();
#endif
    return ret;
}

topic_messenger_ret_t topic_messenger_del_all()
{
    topic_messenger_ret_t ret = TOPIC_MESSENGER_NO_SUBCRIBE;
#if topic_messenger_support_rtos
    mutex_cb.mutex_get_cb();
#endif

    if (register_count == 0)
        goto exit;

    topic_messenger_subscribe_t *tmp = register_head;
    while (tmp != NULL)
    {
        register_head = tmp->next;
        topic_messenger_free_func((void *)tmp->key);
        topic_messenger_free_func(tmp);
        tmp = register_head;
    }
    register_count = 0;
    ret = TOPIC_MESSENGER_SUCCESS;

exit:
#if topic_messenger_support_rtos
    mutex_cb.mutex_give_cb();
#endif
    return ret;
}

topic_messenger_list_t topic_messenger_list_create()
{
    topic_messenger_list_t list = topic_messenger_malloc_func(sizeof(topic_messenger_list_paras_t));
    if (list == NULL)
        return NULL;
    list->node_cnt = 0;
    list->head = NULL;
    return list;
}

topic_messenger_ret_t topic_messenger_list_add(topic_messenger_list_t list, void *userdata, size_t lenth)
{
    if (list == NULL)
        return TOPIC_MESSENGER_LIST_ERR;

    topic_messenger_list_struct_t *node = topic_messenger_malloc_func(sizeof(topic_messenger_list_struct_t));
    if (node == NULL)
        return TOPIC_MESSENGER_MALLOC_FAIL;

    node->userdata = userdata;
    node->lenth = lenth;
    node->next = NULL;

    if (list->head == NULL)
    {
        list->head = node;
    }
    else
    {
        topic_messenger_list_struct_t *head = list->head;
        while (head->next != NULL)
        {
            head = head->next;
        }
        head->next = node;
    }
    list->node_cnt++;
    return TOPIC_MESSENGER_SUCCESS;
}

size_t topic_messenger_list_get_cnt(topic_messenger_list_t list)
{
    if (list == NULL)
        return 0;
    return list->node_cnt;
}

topic_messenger_ret_t topic_messenger_list_destroy(topic_messenger_list_t list)
{
    topic_messenger_list_struct_t *tmp = list->head;
    topic_messenger_list_struct_t *tmp_next = NULL;

    if (list == NULL)
        return TOPIC_MESSENGER_LIST_ERR;

    while (tmp != NULL)
    {
        tmp_next = tmp->next;
        topic_messenger_free_func(tmp);
        tmp = tmp_next;
    }
    topic_messenger_free_func(list);
    return TOPIC_MESSENGER_SUCCESS;
}

topic_messenger_ret_t topic_messenger_list_retrieve(topic_messenger_list_t list, void **userdata, size_t *lenth)
{
    if (list == NULL)
        return TOPIC_MESSENGER_LIST_ERR;

    topic_messenger_ret_t ret = TOPIC_MESSENGER_SUCCESS;

    if (list->node_cnt == 0)
    {
        ret = TOPIC_MESSENGER_LIST_NULL;
        goto exit;
    }

    topic_messenger_list_struct_t *head = list->head;

    *userdata = head->userdata;
    *lenth = head->lenth;

    list->head = head->next;
    list->node_cnt--;

    topic_messenger_free_func(head);

exit:
    if (list->node_cnt == 0)
    {
        topic_messenger_free_func(list);
    }
    return ret;
}

#endif
